﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataSource;
using System.Collections.Concurrent;
using CsvHelperPlus;
using System.IO;
using System.Data;


namespace Strategy.Linkage
{
    public class Linkage
    {
        //ConcurrentDictionary<string, Level2Struct> lv2ht;
        List<DateTime> observeTimeList;
        List<string> tickerList;
        Dictionary<string, double> ta5dDict = new Dictionary<string, double>();
        private string date;
        private int timePos; // 观测时间的播放位置

        TimeSpan leaderEntryTimeSpan; //龙头进入信号时，考虑的时间范围
        TimeSpan followerEntryTimeSpan; //跟随者的机会时间。超出无效
        TimeSpan decayTimeSpan; // 退出信号时，考虑的时间范围
        TimeSpan falseTimeSpan;
        TimeSpan timeout;
        TimeSpan twoMinuteSpan;
        TimeSpan oneMinuteSpan;
        TimeSpan halfMinuteSpan;
        TimeSpan oneSecondSpan;
        TimeSpan snapTimeSpan; //需要保存历史数据的实际范围
        DateTime exitEndTime; //出仓截止时间

        public delegate void SignalEventHandler(Follow fl);
        public event SignalEventHandler OnEntrySignalEvent;
        public event SignalEventHandler OnExitSignalEvent;

        T0Univ tu; // 保存t0univ的相关信息
        Dictionary<string, Leader> leaderDict;
        HashSet<string> followSet; //保存已跟随龙头的股票
        SectorHelp sectHandler;
        string sectorType;

        public Linkage(string date)
        {
            //lv2ht = new ConcurrentDictionary<string, Level2Struct>();
            observeTimeList = new List<DateTime>();
            leaderEntryTimeSpan = new TimeSpan(0, 0, 0, 60);
            followerEntryTimeSpan = new TimeSpan(0, 0, 0, 120);
            decayTimeSpan = new TimeSpan(0, 0, 0, 120);
            falseTimeSpan = new TimeSpan(0, 0, 0, 180);
            timeout = new TimeSpan(0, 0, 0, 120);
            twoMinuteSpan = new TimeSpan(0, 0, 0, 120);
            oneMinuteSpan = new TimeSpan(0, 0, 0, 60);
            halfMinuteSpan = new TimeSpan(0, 0, 0, 30);
            oneSecondSpan = new TimeSpan(0, 0, 0, 1);
            snapTimeSpan = new TimeSpan(0, 0, 0, 180); //保存过去3分钟的历史数据
            tu = new T0Univ(snapTimeSpan);
            leaderDict = new Dictionary<string, Leader>();      
            followSet = new HashSet<string>();
            timePos = 0;
            sectorType = SectorHelp.GetSectorType();
            sectHandler = new SectorHelp(DateUtils.GetLastTradeDate(date));
            this.date = date;
            exitEndTime = GetTheExitSignalEndTime();
            LoadTheLeader();
        }

        public DateTime GetTheExitSignalEndTime(){
            int year = int.Parse(date.Substring(0, 4));
            int month = int.Parse(date.Substring(4, 2));
            int day = int.Parse(date.Substring(6, 2));
            DateTime dt = new DateTime(year, month, day, 14, 55, 0);
            return dt;
        }

        public DateTime GetBeLeaderTime()
        {
            int year = int.Parse(date.Substring(0, 4));
            int month = int.Parse(date.Substring(4, 2));
            int day = int.Parse(date.Substring(6, 2));
            DateTime dt = new DateTime(year, month, day, 8, 0, 0);
            return dt;
        }

        public void Subscrible()
        {
            SimulateMarket sm = SimulateMarket.GetInstance();
            //tickerList = new List<string>();
            //tickerList.Add("603711");
            //tickerList.Add("000002");
            //tickerList.Add("300465");
            //tickerList = sm.GetAllMarketStockList().Take(1000).ToList();
            //tickerList = sm.GetAllMarketStockList();
            //tickerList = GetStockListByRank();
            tickerList = GetStockListFromConcept();
            sm.Subscrible(tickerList, DType.LV2);
            GetAvgTradeAmount();
        }

        private List<string> GetStockListByRank()
        {
            string lastTradeDate = DateUtils.GetLastTradeDate(date);
            SimulateMarket sm = SimulateMarket.GetInstance();
            Dictionary<string, Type> convert = new Dictionary<string, Type>();
            convert.Add("TA_AVG5", typeof(double));
            convert.Add("FLOATINGMARKETCAP", typeof(double));
            convert.Add("SIGMA_20", typeof(double));
            DataTable dt = sm.GetUniv(lastTradeDate, convert: convert);
            dt.Columns.Add("TurnOver", typeof(float));
            //dt.Columns.Add("Sigma", typeof(float));
            //dt.Columns.Add("Amt", typeof(float));
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                if ((double)dt.Rows[i]["TA_AVG5"] < 0 || (double)dt.Rows[i]["FLOATINGMARKETCAP"] < 0)
                {
                    dt.Rows[i]["TurnOver"] = -9999;
                }
                else
                {
                    dt.Rows[i]["TurnOver"] = (double)dt.Rows[i]["TA_AVG5"] / (double)dt.Rows[i]["FLOATINGMARKETCAP"];
                }
                //dt.Rows[i]["TurnOver"] = float.Parse(dt.Rows[i]["TA_AVG5"].ToString())/float.Parse(dt.Rows[i]["FLOATINGMARKETCAP"].ToString());
                //dt.Rows[i]["Sigma"] = float.Parse(dt.Rows[i]["SIGMA_20"].ToString());
                //dt.Rows[i]["Amt"] = float.Parse(dt.Rows[i]["TA_AVG5"].ToString()); 

            }
            List<string> stkListbyAmt = dt.AsEnumerable().OrderByDescending(x => x["TA_AVG5"]).Take((int)(dt.Rows.Count * 0.3)).Select(x => x["#TICKER"].ToString().Substring(0, 6)).ToList();
            List<string> stkListbySigma = dt.AsEnumerable().OrderByDescending(x => x["SIGMA_20"]).Take((int)(dt.Rows.Count * 0.6)).Select(x => x["#TICKER"].ToString().Substring(0, 6)).ToList();
            List<string> stkListbyTurnOver = dt.AsEnumerable().OrderByDescending(x => x["TurnOver"]).Take((int)(dt.Rows.Count * 0.3)).Select(x => x["#TICKER"].ToString().Substring(0, 6)).ToList();
            List<string> stkList = stkListbyAmt.Intersect(stkListbySigma).ToList().Intersect(stkListbyTurnOver).ToList();
            stkList.Sort();
            return stkList;
        }

        public List<string> LoadStockListByAmount()
        {
            string lastTradeDate = DateUtils.GetLastTradeDate(date);
            SimulateMarket sm = SimulateMarket.GetInstance();
            Dictionary<string, Type> convert = new Dictionary<string, Type>();
            convert.Add("TA_AVG5", typeof(double));
            DataTable dt = sm.GetUniv(lastTradeDate, convert: convert);
            List<string> stkListbyAmt = dt.AsEnumerable().Where(x => Convert.ToDouble(x["TA_AVG5"]) >= 10000000).Select(x => x["#TICKER"].ToString().Substring(0, 6)).ToList();
            return stkListbyAmt;
        }

        public List<string> LoadQualifiedStockList() //加载复核条件的股票列表
        {
            var stk_nonST = LoadNonSTStockList();
            var stk_byAmt = LoadStockListByAmount();
            var stk_list = stk_nonST.Intersect(stk_byAmt).ToList();
            return stk_list;
        }



        public List<string> LoadNonSTStockList()
        {
            string lastTradeDate = DateUtils.GetLastTradeDate(date);
            SimulateMarket sm = SimulateMarket.GetInstance();
            DataTable dt = sm.GetUniv(lastTradeDate);
            var stkList = dt.AsEnumerable().Select(x => x["#TICKER"].ToString().Substring(0, 6)).ToList();
            return stkList;
        }


        public void GetAvgTradeAmount()
        {
            string lastTradeDate = DateUtils.GetLastTradeDate(date);
            SimulateMarket sm = SimulateMarket.GetInstance();
            Dictionary<string, Type> convert = new Dictionary<string, Type>();
            convert.Add("TA_AVG5", typeof(double));
            DataTable dt = sm.GetUniv(lastTradeDate, convert: convert);
            foreach (var tk in tickerList)
            {
                var taList = dt.AsEnumerable().Where(x => x["#TICKER"].ToString().Substring(0, 6) == tk).Select(x => x["TA_AVG5"]).ToList();
                if (taList.Count > 0)
                {
                    ta5dDict.Add(tk, (double)taList[0]);
                }
                else
                {
                    ta5dDict.Add(tk, 0);
                }
            }
        }

        public List<string> GetStockListFromConcept()
        {
            List<string> tkList = new List<string>();
            foreach(var ld in leaderDict.Values){
                tkList.Add(ld.code.Substring(0, 6));
                foreach (var fl in ld.followers)
                {
                    tkList.Add(fl.code.Substring(0, 6));
                }
            }
            tkList = tkList.Distinct().ToList();
            tkList.Sort();
            return tkList;
        }


        public void SetObserveTime(DateTime st, DateTime et, int second) //设定观测起始时间，结束时间，观测频率
        {
            TimeSpan interval = new TimeSpan(0, 0, 3);
            while (st <= et)
            {
                observeTimeList.Add(st);
                st = st + interval;
            }
        }


        public List<DateTime> GetTimeSlice()
        {
            return observeTimeList;
        }


        public void OnLevel2Received(Level2Struct ls) //收到行情进行保存
        {
            //lv2ht[ls.code] = ls;
            tu.Add(ls);
        }

        public void OnTimePulse(DateTime dt)  // 时间响应
        {
            tu.TimeSync(dt); // T0Uiv的时间同步
            if (IsOutOfTimeObserve())  //策略观察时间已结束就不响应时间
            {
                return;
            }
            while (GetCurrentTime() <= dt)
            {
                OnObserveTime();
                MoveToNextTime();
                if (IsOutOfTimeObserve()) break;
            }

        }


        public bool IsOutOfTimeObserve()
        {
            return timePos > observeTimeList.Count - 1;
        }

        public bool IsMarkertDataAvailable(string code)
        {
            return SimulateMarket.GetInstance().IsMarketDataAvailable(code);
        }

        public void OnObserveTime()  // 实盘时替换成一个定时器调用的函数就行。
        {
            RunStrategy();
        }

        public DateTime GetCurrentTime()
        {
            return observeTimeList[timePos];
        }

        public void MoveToNextTime()
        {
            timePos++;
        }

        public void RunStrategy() //注意下面的顺序，这样写的目的应该是，如果发出委托命令，交易所得需要在下一个tick去处理订单，但是可能下一句exit就把未成的订单给撤掉了
        {
            
            SendExitSignal(); //
            SendEntrySignal();
        }

        public void LoadTheLeader()
        {
            string lastDate = DateUtils.GetLastTradeDate(date);
            string candiFile = String.Format(@"P:\T0\CoMov\Data\Follower\{0}\{1}\{2}.follower.csv", sectorType, StrategyPara.get_follow_pair_arg_str(), lastDate);
            DataTable dt = CsvHandler.ReadCsvToDataTable(candiFile);
            var leaderList = dt.AsEnumerable().Select(x => new{code=x["Leader"].ToString(), sect=x["ConceptSectorName"].ToString()}).Distinct().ToList();
            //var stkTradableList = LoadQualifiedStockList(); // 按策略要求更改
            foreach(var leader in leaderList)
            {
                if (leader.code == "601929.SH")
                {
                    Console.WriteLine("stop");
                }
                if (!Char.IsDigit(leader.code[0]))
                {
                    continue;
                }
                var follers = dt.AsEnumerable().Where(x => x["Leader"].ToString().Equals(leader.code) && x["ConceptSectorName"].ToString().Equals(leader.sect)).Select(x => x["Follower"]).Distinct().ToList();
                if (leaderDict.ContainsKey(leader.code.ToString().Substring(0,6))) //该龙头可能同属多个板块
                {
                    var ld = leaderDict[leader.code.Substring(0,6)];
                    List<string> followed = ld.followers.AsEnumerable().Select(x => x.code).ToList();//已跟随股票列表
                    ld.sect.Add(leader.sect); 
                    foreach (string tk in follers)
                    {
                        if (!Char.IsDigit(tk[0])) // 排除没有小弟的follower
                        {
                            continue;
                        }
                        if (followed.Contains(tk.Substring(0,6))) //跟随者中已经有个该票，不添加
                        {
                            continue;
                        }
                        //if (!stkTradableList.Contains(tk.Substring(0,6))) continue;  # 所有备选的票应该盘前准备好，不应该在这个程序中去筛选
                        Follow fl = new Follow();
                        fl.code = tk.Substring(0,6);
                        fl.leader = ld.code;
                        fl.sect = leader.sect;
                        ld.followers.Add(fl);
                    }
                }
                else
                {
                    Leader ld = new Leader();
                    ld.code = leader.code.Substring(0,6);
                    ld.ret = 0;
                    ld.vol = 0;
                    ld.sect = new List<string> { leader.sect};
                    List<Follow> follerList = new List<Follow>();
                    foreach (string tk in follers)
                    {
                        if (!Char.IsDigit(tk[0]))
                        {
                            continue;
                        }
                        //if (!stkTradableList.Contains(tk.Substring(0,6))) continue; 
                        Follow fl = new Follow();
                        fl.code = tk.Substring(0,6);
                        fl.leader = ld.code;
                        fl.sect = leader.sect;
                        follerList.Add(fl);
                    }
                    ld.followers = follerList;
                    leaderDict[ld.code] = ld; //加载到leadDict中
                }
                

            }

        }


        public void SendEntrySignal()
        {
            float ret;
            float ret_fl;
            int vol = 0;
            double ta = 0;
            double ta5d = 0;
            DateTime cur_tm = GetCurrentTime();
            foreach (var leader in leaderDict.Keys)
            {
                Leader ld = leaderDict[leader];

                //if (GetCurrentTime() - ld.time > followerEntryTimeSpan) //龙头开始上涨已超过一定时间,就不纳入跟随者了
                //{
                //    continue;
                //}
                ret = tu.CountCurRet(ld.code, cur_tm - halfMinuteSpan); //最近30s涨幅
                ta = tu.CountBalance(ld.code, cur_tm - halfMinuteSpan); //最近30s成交量
                ta5d = ta5dDict[ld.code] / (240 * 2); //5d天的30s成交量
                //ta5d = 0;
                int ret_thresh = StrategyPara.get_ret_thres(); // ret超过多少
                float scale_factor = StrategyPara.get_scale_factor(); // 量超过几倍

                if ((ret > ret_thresh) && (ta > ta5d * scale_factor)) // 确认发出信号
                {
                    if (ld.code == "300560")
                    {
                        Console.WriteLine("stop");
                    }

                    int rising_tm = tu.CountRisingTimeSpan(ld.code, ret * 0.5f, halfMinuteSpan); // 最近上涨一半ret所花时间
                    if (rising_tm < 10f) //上涨时间小于10s，怀疑不是持续上涨情况，去掉
                    {
                        continue;
                    }
                    for (int i = 0; i < ld.followers.Count(); i++)
                    {

                        Follow fl = ld.followers[i];
                        //if (leaderDict.ContainsKey(fl.code)) continue; // 已是龙头，不当小弟
                        //if (followSet.Contains(tk)) continue; //已跟随龙头，不跟随其他龙头 
                        //ret = tu.CountMaxRet(tk, GetCurrentTime() - ld.time); // 龙头开始到2分钟结束之前，任意时刻满足要求就好

                        //if (GetCurrentTime() - ld.time < halfMinuteSpan) //小于30s的去掉
                        //{
                        //    continue;
                        //}
                        ret_fl = tu.CountCurRet(fl.code, cur_tm - halfMinuteSpan);
                        if (ret_fl > ret - 100) continue; //如果小弟已经涨起来了，就算了，不进了

                        if (!IsMarkertDataAvailable(fl.code)) //交易所没有这票行情就不发信号
                        {
                            continue;
                        }
                        if (fl.sigStatus != SignalState.noSignalSended) //该跟随者已经发送过信号了，就不发了
                        {
                            continue;
                        }
                        ld.time = GetCurrentTime(); //这个时候确定龙头有行情的时间
                        fl.entryRet = ret; // 进入时，需要根据哪个ret判断，就记录哪个ret
                        fl.vol = vol;
                        fl.amt = ta;
                        fl.leader = ld.code;
                        fl.time = GetCurrentTime();
                        fl.sigStatus = SignalState.enterSignalSended; //准备发送进入信号
                        fl.leaderTime = ld.time;
                        //fl.sect = sectHandler.GetBothInSect(ld.code, fl.code)[0]; //公共板块
                        fl.sect = ld.sect[0];
                        //followSet.Add(tk); //列入有主（龙头）列表
                        OnEntrySignalEvent(fl);
                    }
                }
                
            }

        }

        

        public void SendExitSignal()
        {
            float ret;
            int vol = 0;
            foreach (var key in leaderDict.Keys.ToList())
            {
                Leader ld = leaderDict[key];
                for (int i = 0; i < ld.followers.Count; i++)
                {
                    Follow fl = ld.followers[i];
                    
                    if (fl.sigStatus == SignalState.exitSignalSended) //已经退出，就不用进行下面的判断
                    {
                        continue;
                    }
                    if (fl.sigStatus == SignalState.noSignalSended) //还没进仓，当然不用出仓
                    {
                        continue;
                    }
                    if ((fl.code == "600037") && (ld.code == "601929"))
                    {
                        ;
                    }
                    if (GetCurrentTime() >= exitEndTime)
                    {
                        fl.sigStatus = SignalState.exitSignalSended;
                        fl.exitReason = ExitReason.endTime; //到了截止时间
                        followSet.Remove(fl.code);
                        OnExitSignalEvent(fl);
                        continue;
                    }
                    TimeSpan span = GetCurrentTime() - fl.time; //进入信号发出后，至今的时间间隔
                    //if (span > timeout) //超时
                    //{
                    //    fl.sigStatus = SignalState.exitSignalSended;
                    //    fl.exitReason = ExitReason.timeOut;
                    //    followSet.Remove(fl.code); //取得自由身后，可以跟随新的龙头
                    //    OnExitSignalEvent(fl);
                    //    continue;
                    //}

                    TimeSpan para_span = StrategyPara.get_exit_time_span(); //出仓时间考察参数
                    
                    // 进仓x秒后开始计算
                    if (span >= para_span) //假信号
                    {
                        ret = tu.CountCurRet(fl.code, GetCurrentTime() - para_span); //最近x秒涨幅
                        if (ret < 10)
                        {
                            fl.sigStatus = SignalState.exitSignalSended;
                            fl.exitReason = ExitReason.falsePositive;
                            fl.exitRet = ret;
                            followSet.Remove(fl.code);
                            OnExitSignalEvent(fl);
                            continue;
                        }
                    }
                    //if ((span >= para_span)) //信号衰减
                    if ((span >= oneSecondSpan)) //信号衰减
                    {
                        float retLeader = tu.CountCurRet(ld.code, GetCurrentTime() - halfMinuteSpan);
                        //float retFollow = tu.CountCurRet(fl.code, GetCurrentTime() - halfMinuteSpan);
                        if ((retLeader < -10) /*&& (retFollow <10)*/)
                        {
                            fl.sigStatus = SignalState.exitSignalSended;
                            fl.exitReason = ExitReason.signalDecay;
                            fl.exitRet = retLeader;
                            followSet.Remove(fl.code);
                            OnExitSignalEvent(fl);
                            continue;
                        }
                    }

                    if ((span >= twoMinuteSpan)) //没有发生联动
                    {
                        float retFollower = tu.CountCurRet(fl.code, GetCurrentTime() - twoMinuteSpan);
                        if (retFollower < 200)
                        {
                            fl.sigStatus = SignalState.exitSignalSended;
                            fl.exitReason = ExitReason.notComov;
                            fl.exitRet = retFollower;
                            followSet.Remove(fl.code);
                            OnExitSignalEvent(fl);
                            continue;
                        }

                    }

                    ret = tu.CountCurRet(fl.code, GetCurrentTime() - span); //进仓以来的return
                    if (ret < -100)
                    {
                        fl.sigStatus = SignalState.exitSignalSended;
                        fl.exitReason = ExitReason.stopLoss;
                        fl.exitRet = ret;
                        followSet.Remove(fl.code);
                        OnExitSignalEvent(fl);
                        continue;
                    }

                    //if (span >= halfMinuteSpan) //止盈
                    //{
                    //    ret = tu.CountCurRet(fl.code, GetCurrentTime() - halfMinuteSpan);
                    //    if (ret > 100)
                    //    {
                    //        fl.sigStatus = SignalState.exitSignalSended;
                    //        fl.exitReason = ExitReason.takeProfit;
                    //        fl.exitRet = ret;
                    //        followSet.Remove(fl.code);
                    //        OnExitSignalEvent(fl);
                    //        continue;
                    //    }
                    //}

                }
                //if (GetCurrentTime() - ld.time > new TimeSpan(0, 5, 0)) //5分钟后如果龙头还没有跟随者，就kill掉该龙头
                //{
                //    if (ld.followers.Count == 0)
                //    {
                //        leaderDict.Remove(ld.code);
                //    }
                //}

            }

        }



        public void Save(string path)
        {
            string dir = String.Format(@"{0}\Leaders", path);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            foreach (var file in Directory.GetFiles(dir))//删除该目录下原有文件
            {
                File.Delete(file);
            }

            foreach (var key in leaderDict.Keys)
            {
                Leader ld = leaderDict[key];
                string file = dir + "\\" + ld.code + ".csv";
                if (ld.followers.Count > 0)
                {
                    CsvHandler.ListSave2CSV(file, ld.followers);
                }
            }
        }


    }

    public class Leader
    {
        public string code;
        public List<string> sect;
        public List<Follow> followers;
        //public List<string> candidates;
        public Hashtable candidates; //成为follow的候选人，纳入观察的对象, value为对应板块
        public float ret; // 成为leader时的涨幅
        public float vol; // 成为leader时的1分钟成交量
        public DateTime time; // 成为leader的时间
        public DateTime dealTime; // 退出龙头的时间(如果其follow都已出仓,该龙头算作结束）
        public bool isDead; // 龙头是否结束
        public Leader()
        {
            isDead = false;
            sect = new List<string>();
            followers = new List<Follow>();
            //candidates = new List<string>(); // Leader所属板块的所有股票
            candidates = new Hashtable();
        }
    }

    public class Follow
    {
        public string code;
        public string leader;
        public DateTime leaderTime;
        public string sect; //与龙头同属的板块
        public float entryRet;
        public float exitRet;
        public float vol;
        public double amt;
        public DateTime time; //成为跟屁虫的时间
        public SignalState sigStatus; //该follow是否正要进入
        public ExitReason exitReason;
        public Follow()
        {
            entryRet = 0;
            exitRet = 0;
            sigStatus = SignalState.noSignalSended;
            exitReason = ExitReason.notExit; //默认值
        }
    }

    public enum SignalState
    {
        noSignalSended = 0, //未发进仓信号
        enterSignalSended = 1, //已发进仓信号
        exitSignalSended = 2 // 已发出仓信号
    }


    public enum ExitReason
    {
        notExit = 0, //针对买单
        timeOut = 1, //超时
        signalDecay = 2, //信号衰减
        falsePositive = 3,//误报
        takeProfit = 4, //止盈
        endTime=5, //到截止时间
        notComov=6, //没有发生联动
        stopLoss=7 //止损
    }

    static public class StrategyPara
    {
        static int ret_thres;
        static float scale_factor;
        static TimeSpan exit_span;
        static int num_leader;
        static int pair_day;
        static public void set_para(int ret_thres, float scale_factor, int span, int num_leader, int pair_day)
        {
            StrategyPara.ret_thres = ret_thres;
            StrategyPara.scale_factor = scale_factor;
            StrategyPara.exit_span = new TimeSpan(0, 0, 0, span);
            StrategyPara.num_leader = num_leader;
            StrategyPara.pair_day = pair_day;
        }

        static public int get_ret_thres()
        {
            return ret_thres;
        }

        static public float get_scale_factor()
        {
            return scale_factor;
        }

        static public TimeSpan get_exit_time_span()
        {
            return exit_span;
        }

        static public string get_follow_pair_arg_str()
        {
            return String.Format("NL[{0}]_PD[{1}]", StrategyPara.num_leader, StrategyPara.pair_day);
        }

        static public string get_backtest_arg_str()
        {
            return String.Format(@"Para_ret[{0}]_scale[{1:.00}]_span[{2}]", ret_thres, scale_factor, exit_span.TotalSeconds);
        }
    }

}